/********************************************************************************************************************************
 * 《C ++ Primer》第五版中文版，读书笔记：按照书中的的示例源码和每一个小章节的课后习题，自己动手写代码实现，作为联系和测试。
 * Date: 2024-04-01 09:20
 * Author: dimon.chen 
 * EMali: 1181302388@qq.com 
 * 
 * 章节: 第三章 字符串，向量和数组
 *       3.3.3 vector对象的其它操作
 * 
 ********************************************************************************************************************************/

#include <iostream>
#include <string>
#include <vector>
#include <cctype>

using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;

int main(int argc, char *argv[])
{
    ///
    /// 3.3.3 节练习
    /// 练习3.16: 编写一段程序，把练习3.13中 vector 对象的容量和具体内容输出出来。
    /// 检验你之前的回答是否正确，如果不对，请回来重新学习3.3.1一节
    ///

    cout << "3.13 a:" << endl;
    vector<int> v1;
    cout << "size=" << v1.size() << endl;
    for(vector<int>::size_type idx=0; idx < v1.size(); idx++){
        cout << "v1[" << idx << "]=" << v1[idx] << endl;
    }
    cout << endl;


    cout << "3.13 b" << endl;
    vector<int> v2(10);
    cout << "size=" << v2.size() << endl;
    for(vector<int>::size_type idx=0; idx<v2.size(); idx++)
    {
        cout << "v2[" << idx << "]=" << v2[idx] << " ";
    }
    cout << endl;


    cout << "3.13 c" << endl;
    vector<int> v3(10, 42);             //值初始化，vector对象中有10个元素，每个元素的的值都是42
    cout << "size=" << v3.size() << endl;
    for(vector<int>::size_type idx=0; idx != v3.size(); idx++)
        cout << "v3[" << idx << "]=" << v3[idx] << " ";
    cout << endl;



    cout << "3.13 d" << endl;
    vector<int> v4{10};             //列表初始化，vector对象容量为1
    cout << "size=" << v4.size() << endl;
    for(decltype(v4.size()) idx=0; idx != v4.size(); idx++)
        cout << "v4[" << idx << "]=" << v4[idx];
    cout << endl;


    cout << "3.13 e" << endl;
    vector<int> v5{10, 42};         //列表初始化，vector对象容量为2，其中有两个元素
    cout << "size=" << v5.size() << endl;
    for(auto ival : v5)
        cout << ival << " ";
    cout << endl;


    cout << "3.13 f" << endl;
    vector<string> v6{10};          //使用花括号的形式提供初始值作为列表初始化，但是值类型为int型，不能作为列表初始化
                                    //编译器尝试使用10做直接初始化
                                    //列表中有10个元素，每个元素的值为空string对象
    if(v6.empty())
        cout << "v6 is empty" << endl;
    else
        cout << "v6 size = " << v6.size() << endl;
    
    for(auto svalue : v6)
        cout << "svalue.size()=" << svalue.size() << " is empty=" << svalue.empty() << endl;
    



    cout << "3.13 g" << endl;
    vector<string> v7{10, "hi"};    //虽然是通过花括号提供2个初始值，但第一个初始值是整型不能作为列表中元素中初值
                                    //编译器尝试使用直接初始化
                                    //vector对象中10个元素
    if(v7.empty())
        cout << "v7 is empty" << endl;
    else
        cout << "v7.size()=" << v7.size() << endl;
    
    for(vector<string>::size_type idx=0; idx < v7.size(); idx++)
        cout << "v7[" << idx << "]=" << v7[idx] << " ";
    cout << endl;



    //使用size_type，需要说定是定义在那种类型中的
    vector<string>::size_type len;





    /*******************************************************************************************************************/
    /*******************************************************************************************************************/
    /*******************************************************************************************************************/

    ///
    /// 3.3.3 节练习
    /// 练习3.17: 从cin读入一组词并把它们存入一个vector对象，然后设法把所有词都改写为大写形式。输出改变后的结果，
    ///           每个词占一行
    ///

    string word;                //默认初始化，定义一个空string对象，一个空串
    vector<string> result;      //定义一个空vector对象
    while(cin >> word){
        result.push_back(word); //vector对象push_back成员函数，把值作为vector对象的尾元素，压到vector的尾部(back)
        if(word == "bye")
            break;
    }
    cout << "read size=" << result.size() << endl;
    cout << "you enter:" << endl;
    for(auto svalue : result)
        cout << svalue << endl;


    for(auto svalue: result){   //svalue需要的定义为 std::string & 引用类型
                                //svalue 需要定义为引用类型，如果要通过变量修改vector对象中的元素的值
        for(auto &c : svalue){  //c是引用，c的类型是是用关键字auto类型说明符让编译器推断变量的类型
            c = toupper(c);
        }
    }

    for(string svalue : result){
        cout << svalue << " ";
    }
    cout << endl;


    //使用范围for，如果要修改 vector 容器对象中的元素，循环控制变量需要定义为 引用类型
    for(auto &svalue: result){      //svalue需要的定义为 std::string & 引用类型
                                    //svalue 需要定义为引用类型，如果要通过变量修改vector对象中的元素的值
        for(auto &c : svalue){      //c是引用，c的类型是是用关键字auto类型说明符让编译器推断变量的类型
            c = toupper(c);
        }
    }

    for(string svalue : result){
        cout << svalue << " ";
    }
    cout << endl;

    //或者使用下标运算符，下标运算符返回对应位置上元素的引用，对引用赋值就修改了对应位置上的元素

    for(vector<string>::size_type idx=0; idx<result.size(); idx++)
    {
        string &svalue = result[idx];           //svalue是引用类型，因为要修改vector对象总元素的值

        for(string::size_type cidx=0; cidx < svalue.size(); cidx++)
        {
            svalue[cidx] = '*';                 //下标运算符返回序列中对应位置元素的引用，给引用赋值，修改了对应元素的值
        }
    }
    for(auto svalue : result)
        cout << svalue << " ";
    cout << endl;




    /*******************************************************************************************************************/
    /*******************************************************************************************************************/
    /*******************************************************************************************************************/

    ///
    /// 3.3.3 节练习
    /// 练习3.18：下面的程序合法么？如果不合法，你准备怎么修改它
    ///
    vector<int> ivec;       //默认初始化ivec时一个空vector对象
    //ivec[0] = 42;           //错误：ivec是一个空string对象，其中元素的个数为0个，使用下标运算符只能访问
                            //确认已知的vector成员，对空vector对象使用不再合法范围类的下标值访问，会引发不可预知的后果

    /* 运行报错：
     * ** ** ** *** *** 
      段错误 (核心已转储)
     */

    ivec.push_back(42);     //正确做法：使用vector类型成员函数push_back()把值作为尾元素，push压到vector对象尾部(back)




    ///
    /// 3.3.3 节练习
    /// 练习3.19：如果想定义一个含有10个元素的vector对象，素有元素的值都是42，请列举出3种不同的实现方法。那总方法更好为什么
    ///
    vector<int> ivec1(10,42);
    vector<int> ivec2{42, 42, 42, 42, 42, 42, 42, 42, 42, 42};
    vector<int> ivec3 = ivec2;
    vector<int> ivec4(ivec2);

    vector<int> ivec5;
    for(int i=1; i<=10; i++){
        ivec5.push_back(42);
    }

    cout << "iveci.size()=" << ivec1.size() << endl;
    cout << "iveci.size()=" << ivec2.size() << endl;
    cout << "iveci.size()=" << ivec3.size() << endl;
    cout << "iveci.size()=" << ivec4.size() << endl;
    cout << "iveci.size()=" << ivec5.size() << endl;

    for(auto i : ivec1)
        cout << i << " ";
    cout << endl;

    for(auto i : ivec2)
        cout << i << " ";
    cout << endl;

    for(auto i : ivec3)
        cout << i << " ";
    cout << endl;

    for(auto i : ivec4)
        cout << i << " ";
    cout << endl;

    for(auto i : ivec5)
        cout << i << " ";
    cout << endl;    


    ///
    /// 3.3.3 节练习
    /// 练习3.20: 读取一组整数，把它存入一个vector对象，将每对相邻整数的和输出处理。
    ///           修改程序，注册要求先输出第一个和最后一个元素的和，然后输出第二个和倒数第二元素的和
    ///


    int ival;
    vector<int> numbers; //一个空vector对象，在程序运行时动态添加元素到vector

    while(cin >> ival)
    {
        numbers.push_back(ival);
    }
    for(int ival : numbers)
        cout << ival << " ";
    cout << endl;

    for(vector<int>::size_type i=0; i < numbers.size() && i+1 < numbers.size(); i+=2){
        cout << "sum of " << numbers[i] << " and " << numbers[i+1] << " = " << numbers[i] + numbers[i+1] << endl; 
    }
    cout << endl;


    return 0;
}